#include "InsRspHeaderRecvHandler.h"
#include "BeginConnInsDestHandler.h"
#include "BeginConnectOriDestHandler.h"
#include "InsRspHeaderSendHandler.h"
#include "HttpResponseHeader.h"
#include "GlobalContext.h"

using namespace std;
using namespace log4cplus;

Logger InsRspHeaderRecvHandler::log=GetLogger(LOG4CPLUS_TEXT("InsRspHeaderRecvHandler"));

void InsRspHeaderRecvHandler::GetRecvInfo(ClientContext &client,SOCKET *recvSock,WSABUF **recvBuffer,OVERLAPPED **recvOvl,HttpResponseHeader **responseHeader)
{
	unsigned int clienSequenceNo=client.SequenceNo();
	*recvSock=client.InsteadContext().TempSock();
	*recvBuffer=client.InsteadContext().TempBuffer();
	*recvOvl=client.InsteadContext().TempOVL();
	*responseHeader=&(client.InsteadContext().TempHttpResponseHeader());
	LOG4CPLUS_DEBUG_FMT(log,LOG4CPLUS_TEXT("[Client%d]Set instead server's response header recvsend info."),clienSequenceNo);
}

ITransHandler::ExecuteResultCode InsRspHeaderRecvHandler::OnHeaderReceiveCompleted(ClientContext &client,OVERLAPPED *ovl,HttpResponseHeader &headerData)
{
	unsigned int clienSequenceNo=client.SequenceNo();
	ExecuteResultCode ret=ITransHandler::ExecuteOK;
	if(headerData.StatusCode()==302)
	{
		//302-Redirect
		LOG4CPLUS_DEBUG_FMT(log,LOG4CPLUS_TEXT("[Client%d]Response code is 302,start to redirect."),clienSequenceNo);
		map<string,string>::iterator iter=headerData.Headers().find("Location");
		InsteadHttpUrl url(iter->second.substr(1));
		ret=OnRedirectConnect(client,ovl,url);
	}
	else if(headerData.StatusCode()==200||headerData.StatusCode()==206)
	{
		//200-OK,206-Partial Content
		if(!headerData.SetRequestRangeWithCheck(client.TranslatedFileIndex(),client.MaxFileIndex()))
		{
			LOG4CPLUS_DEBUG_FMT(log,LOG4CPLUS_TEXT("[Client%d]Response is ok,but set request range and check failed."),clienSequenceNo);
			ret=OnExecuteError(client,ovl,ITransHandler::ExecuteFatalError);
		}
		else
		{
			LOG4CPLUS_DEBUG_FMT(log,LOG4CPLUS_TEXT("[Client%d]Receive all response header data successed,start to transfer."),clienSequenceNo);
			ret=OnSendResponseHeader(client,headerData);
		}
	}
	else
	{
		ret=OnExecuteError(client,ovl,ITransHandler::ExecuteFatalError);
	}
	return ret;
}

ITransHandler::ExecuteResultCode InsRspHeaderRecvHandler::OnRedirectConnect(ClientContext &client,OVERLAPPED *ovl,const InsteadHttpUrl &url)
{
	client.FreeInsteadContext();
	delete client.SetCurrentHandler(new BeginConnInsDestHandler(url));
	::PostQueuedCompletionStatus(GlobalContext::Instance().IOCP(),0,static_cast<ULONG_PTR>(client.SequenceNo()),ovl);
	return ITransHandler::ExecuteOK;
}

ITransHandler::ExecuteResultCode InsRspHeaderRecvHandler::OnExecuteError(ClientContext &client,OVERLAPPED *ovl,ITransHandler::ExecuteResultCode executeResult)
{
	delete client.SetCurrentHandler(new BeginConnectOriDestHandler());
	client.FreeInsteadContext();
	LOG4CPLUS_DEBUG_STR(log,LOG4CPLUS_TEXT("Receive instead server response data failed(free instead context),try to connect original server."));
	::PostQueuedCompletionStatus(GlobalContext::Instance().IOCP(),0,static_cast<ULONG_PTR>(client.SequenceNo()),ovl);
	return ITransHandler::ExecuteOK;
}

ITransHandler::ExecuteResultCode InsRspHeaderRecvHandler::OnSendResponseHeader(ClientContext &client,HttpResponseHeader &headerData)
{
	client.ReplaceDestinationWithInsteadContext();
	return RspHeaderRecvHandlerBase::OnSendResponseHeader(client,headerData);
}

ITransHandler* InsRspHeaderRecvHandler::GetNextHandler()
{
	return new InsRspHeaderSendHandler();
}